﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace CommonLib
{
	/// <summary>
	/// This is the new class that I'm using to log events using System.Diagnostics
	/// </summary>
	public class Tracer
	{
		[ThreadStatic()]
		internal static TraceSource ts = null;
		[ThreadStatic()]
		internal static Stack<TraceActivity> activities = null;

		public static void Start()
		{
			ts = new TraceSource(CommonLib.CommonLibSettings.Default.DiagnosticsSource);
			activities = new Stack<TraceActivity>();
		}

		public static void Stop()
		{
			if (ts == null)
				return;
			ts.Close();
		}

		public static void StartActivity(String activityName)
		{
			if (activities == null)
				activities = new Stack<TraceActivity>();
			if (ts == null)
				ts = new TraceSource(CommonLib.CommonLibSettings.Default.DiagnosticsSource);
			if (String.IsNullOrEmpty(activityName))
				return;

			TraceActivity newActivity = new TraceActivity(activityName, Trace.CorrelationManager.ActivityId);
			activities.Push(newActivity);
			Guid nextGuid = Guid.NewGuid();
			ts.TraceTransfer(0, "Entering " + activityName, nextGuid);
			Trace.CorrelationManager.ActivityId = nextGuid;
			ts.TraceData(TraceEventType.Start, 0, activityName);
		}

		public static void EndActivity(String activityName)
		{
			if (activities == null || activities.Count <= 0)
				return;
			if (ts == null)
				return;
			if (String.IsNullOrEmpty(activityName))
				return;

			TraceActivity top = null;
			do
			{
				top = activities.Pop();
				if (top == null)
				{
					activities.Clear();
					break;
				}
			}
			while (top.ActivityName.Equals(activityName) == false
				&& activities.Count > 0);

			if (activities.Count <= 0)
				return;

			ts.TraceData(TraceEventType.Stop, 0, top.ActivityName);
			ts.TraceTransfer(0, "Exiting " + top.ActivityName, top.ActivityId);
			Trace.CorrelationManager.ActivityId = top.ActivityId;

			ts.Flush(); // I don't have to worry about perf, so I can flush often
		}

		public static void ReportError(String message)
		{
			ReportData(TraceEventType.Error, message);
		}

		public static void ReportError(String message, Exception ex)
		{
			ReportData(TraceEventType.Error, message, ex);
		}

		public static void ReportWarning(String message)
		{
			ReportData(TraceEventType.Warning, message);
		}

		public static void ReportWarning(String message, Exception ex)
		{
			ReportData(TraceEventType.Warning, message, ex);
		}

		public static void ReportInformation(String message)
		{
			ReportData(TraceEventType.Information, message);
		}
		public static void ReportInformation(String message, Exception ex)
		{
			ReportData(TraceEventType.Information, message, ex);
		}
		public static void ReportVerbose(String message)
		{
			ReportData(TraceEventType.Verbose, message);
		}
		public static void ReportVerbose(String message, Exception ex)
		{
			ReportData(TraceEventType.Verbose, message, ex);
		}
		public static void ReportData(TraceEventType eventType, String message, Exception ex)
		{
			ReportData(eventType, message + "\r\n" + ex.Message);
		}
		public static void ReportData(TraceEventType eventType, String message)
		{
			try
			{
				if (ts == null)
					ts = new TraceSource(CommonLib.CommonLibSettings.Default.DiagnosticsSource);
				ts.TraceData(eventType, 0, message);
			}
			catch (Exception)
			{
				/// no idea at this point
			}
		}
	}

	class TraceActivity
	{
		public TraceActivity(String activityName, Guid activityId)
		{
			this.ActivityName = activityName;
			this.ActivityId = activityId;
		}
		public String ActivityName;
		public Guid ActivityId;
	}
}
